Kubernetesダッシュボードのインターネット公開を検出するGuardDutyイベントを発生させてみた
コンサル部のとばち(@toda_kk)です。
先日、GuardDutyがAmazon EKSに対応し、EKSクラスターにおける脅威を検出できるようになりました。
検出できる脅威のタイプ(Finding Types)のうちPolicy:Kubernetes/ExposedDashboardがあります。これは、EKSクラスターにおいてKubernetesダッシュボードがインターネットに公開されたことを検出するイベントです。
実際にどんなイベントが検出されるのか確認したかったので、本記事ではKubernetesダッシュボードをインターネットに公開する手順について記載します。
Kubernetesダッシュボードとは?
Kubernetesダッシュボードは、Kubernetesリソースを管理するためのWebベースのUIです。
Amazon EKSやKubernetesクラスターには通常、デフォルトでは含まれていませんが、デプロイのためのマニフェストファイルが公式で用意されています。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
Kubernetesクラスターにダッシュボードをデプロイすることで、ブラウザ上からコンテナをデプロイしたりKubernetesリソースを修正したりといった操作が可能になります。より詳細な情報については、下記のKubernetes公式ドキュメントをご参照ください。
Policy:Kubernetes/ExposedDashboardの発生条件
AWS公式ドキュメントには、下記のように記載されています。
This finding informs you that Kubernetes dashboard for your cluster was exposed to the internet by a Load Balancer service. An exposed dashboard makes the management interface of your cluster accessible from the internet and allows adversaries to exploit any authentication and access control gaps that may be present.
KubernetesダッシュボードがLoadBalancerタイプのServiceを通じてインターネットに公開されたときに発生するようです。
KubernetesではServiceというリソースを通じてPodへのルーティングや負荷分散を実現します。Serviceにはさまざまなタイプがありますが、このうちLoadBalancerタイプでServiceリソースを作成してKubernetesダッシュボードをインターネットに公開することが、GuardDutyイベントPolicy:Kubernetes/ExposedDashboardの発生条件となっているようです。
Kubernetesダッシュボードをインターネットに公開する手順
前提として、EKSクラスターはすでに作成済みとします。eksctl
によるクラスター作成については、下記の記事をご参照ください。
今回はtest-eks
という名前でEKSクラスターを作成しておきます。
その上で、EKSクラスターでKubernetesダッシュボードをデプロイします。単にデプロイしてローカルからアクセスするだけなら上述のコマンドを実行すれば良いのですが、今回はServiceを通じてインターネットに公開したいので、マニフェストファイルをダウンロードした上でServiceリソースの設定を書き換えます。
$ curl -O https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
Servicekubernetes-dashboard
にspec.type
の行を追加し、LoadBalancer
を指定します。
# Serviceリソースを抜粋 kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: LoadBalancer # ←ここを追加する ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard
その上で、kubectl apply
を実行してKubernetesダッシュボードをデプロイします。
$ kubectl apply -f recommended.yaml
なお、上記手順の作成のために、下記ページを参考にしました。
GuardDutyイベントの確認
上記のマニフェストファイルをapplyすると、EKSクラスターの監査ログ(Audit)からGuardDutyがKubernetesダッシュボードのインターネット公開を検知し、下記のようなJSON形式のイベントが作成されます。
下記は2022年4月現在のものになります。フォーマットなど今後変更になる可能性もあるのでご注意ください。
[ { "AccountId": "123456789012", "Arn": "arn:aws:guardduty:ap-northeast-1:123456789012:detector/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/finding/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "CreatedAt": "2022-04-05T04:00:50.722Z", "Description": "The Kubernetes Dashboard in EKS Cluster test-eks was made accessible to the Internet. If this behavior is not expected, it may indicate a configuration mistake or that your credentials are compromised.", "Id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Partition": "aws", "Region": "ap-northeast-1", "Resource": { "AccessKeyDetails": { "AccessKeyId": "ASIAXXXXXXXXXXXXXXXX", "PrincipalId": "AROAXXXXXXXXXXXXXXXXX", "UserName": "user-name", "UserType": "Role" }, "EksClusterDetails": { "Name": "test-eks", "Arn": "arn:aws:eks:ap-northeast-1:123456789012:cluster/test-eks", "VpcId": "vpc-xxxxxxxxxxxxxxxxx", "Status": "ACTIVE", "Tags": [ { "Key": "aws:cloudformation:stack-name", "Value": "eksctl-test-eks-cluster" }, { "Key": "alpha.eksctl.io/cluster-name", "Value": "test-eks" }, { "Key": "aws:cloudformation:stack-id", "Value": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/eksctl-test-eks-cluster/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, { "Key": "eksctl.cluster.k8s.io/v1alpha1/cluster-name", "Value": "test-eks" }, { "Key": "aws:cloudformation:logical-id", "Value": "ControlPlane" }, { "Key": "alpha.eksctl.io/eksctl-version", "Value": "0.90.0" } ], "CreatedAt": "2022-04-05T01:02:44.349Z" }, "KubernetesDetails": { "KubernetesUserDetails": { "Username": "kubernetes-admin", "Uid": "heptio-authenticator-aws:123456789012:AROAXXXXXXXXXXXXXXXXX", "Groups": [ "system:masters", "system:authenticated" ] } }, "ResourceType": "EKSCluster" }, "SchemaVersion": "2.0", "Service": { "Action": { "ActionType": "KUBERNETES_API_CALL", "KubernetesApiCallAction": { "RequestUri": "/api/v1/namespaces/kubernetes-dashboard/services/kubernetes-dashboard", "Verb": "patch", "UserAgent": "kubectl/v1.22.4 (darwin/amd64) kubernetes/b695d79", "RemoteIpDetails": { "City": { "CityName": "Chiyoda-ku" }, "Country": { "CountryName": "Japan" }, "GeoLocation": { "Lat": xx.xxxx, "Lon": xxx.xxxx }, "IpAddressV4": "xxx.xxx.xxx.xxx", "Organization": { "Asn": "1234", "AsnOrg": "XXXXXXXXXX", "Isp": "XXXXXXXXXX", "Org": "XXXXXXXXXX" } }, "StatusCode": 200, "Parameters": "{\"kind\":\"Service\",\"metadata\":{\"name\":\"kubernetes-dashboard\",\"namespace\":\"kubernetes-dashboard\",\"uid\":\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\"resourceVersion\":\"37041\",\"creationTimestamp\":\"2022-04-05T02:11:24Z\",\"labels\":{\"k8s-app\":\"kubernetes-dashboard\"},\"managedFields\":[{\"manager\":\"kubectl-client-side-apply\",\"operation\":\"Update\",\"apiVersion\":\"v1\",\"time\":\"2022-04-05T03:59:48Z\",\"fieldsType\":\"FieldsV1\",\"fieldsV1\":{\"f:metadata\":{\"f:annotations\":{\".\":{},\"f:kubectl.kubernetes.io/last-applied-configuration\":{}},\"f:labels\":{\".\":{},\"f:k8s-app\":{}}},\"f:spec\":{\"f:externalTrafficPolicy\":{},\"f:ports\":{\".\":{},\"k:{\\\"port\\\":443,\\\"protocol\\\":\\\"TCP\\\"}\":{\".\":{},\"f:port\":{},\"f:protocol\":{},\"f:targetPort\":{}}},\"f:selector\":{\".\":{},\"f:k8s-app\":{}},\"f:sessionAffinity\":{},\"f:type\":{}}}}]}}" } }, "Archived": false, "Count": 1, "DetectorId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "EventFirstSeen": "2022-04-05T03:59:48.638Z", "EventLastSeen": "2022-04-05T03:59:48.665Z", "ResourceRole": "TARGET", "ServiceName": "guardduty", "AdditionalInfo": { "Value": "{}", "Type": "default" } }, "Severity": 5, "Title": "The Kubernetes Dashboard was exposed to the Internet.", "Type": "Policy:Kubernetes/ExposedDashboard", "UpdatedAt": "2022-04-05T04:00:50.722Z" } ]
LoadBalancerタイプのServiceで公開したときのみ通知されるので注意
上述の通り、脅威のタイプがPolicy:Kubernetes/ExposedDashboardのイベントの発生条件は、「KubernetesダッシュボードがLoadBalancerタイプのServiceを通じてインターネットに公開されたとき」です。
そのため、LoadBalancer以外のServiceを通じてKubernetesダッシュボードをインターネットに公開したとしても、GuardDutyは通知してくれません。
また、AWS Load Balancer Controllerなどを利用してIngressリソースを通じてKubernetesダッシュボードをインターネットに公開したとしても、同様に通知されません。
つまり、あくまでもLoadBalancerタイプのServiceを通じてインターネットに公開されたときに通知される、という点にご注意ください。
以上、コンサル部のとばち(@toda_kk)でした。